package calao.client.ui;

import java.util.HashSet;

import calao.client.util.Arrays;

import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ChangeListenerCollection;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.SourcesChangeEvents;
import com.google.gwt.user.client.ui.Widget;

public abstract class NumberedListBox
extends Composite
implements SourcesChangeEvents, ChangeListener
{
	
	public final static int DROPDOWN_LIST = 1;
	public final static int CHECK_LIST = 2;
	public final static int LIST = 3;
	
	public final static String NULL_TEXT = "--";
	
	interface ListWidget {
		public void clear();
		public void addItem(String text, String value);
		public void setItemSelected(int index, boolean selected);
		public int getItemCount();
		public String getValue(int index);
		public String getItemText(int index);
		public boolean isItemSelected(int index);
		public void setEnabled(boolean b);
	}
	
	class ListBoxWrapper extends ListBox implements ListWidget { 
		ListBoxWrapper(boolean isMultipleSelect) {
			super(isMultipleSelect);
			addChangeListener(NumberedListBox.this);
		}
	}
	
	final ChangeListenerCollection listeners = new ChangeListenerCollection();

	boolean sorted = true;
	int firstSortableItem = 0;
	final ListWidget list;
	int[] index = new int[0]; // gives item index for a given box index
	
	final HashSet selectedSet = new HashSet();
	
	public NumberedListBox()
	{
		this(DROPDOWN_LIST);
	}
	
	public NumberedListBox(int type)
	{
		Widget widget;
		switch (type) {
		case DROPDOWN_LIST:
			widget = new ListBoxWrapper(false);
			break;
		case CHECK_LIST:
			widget = new CheckList(this);
			break;
		case LIST:
			widget = new ListBoxWrapper(true);
			break;
		default:
			throw new IllegalArgumentException();
		}
		this.list = (ListWidget)widget;
		initWidget(widget);
	}
	
	public void setSorted(boolean sorted)
	{
		this.sorted = sorted;
	}
	
	private String getBoxText(int boxIndex)
	{
		return getItemText(index[boxIndex]);
	}
	
	private String getBoxValue(int boxIndex)
	{
		return ""+getItemNumber(index[boxIndex]);
	}

	private void sort()
	{
		for (int i=firstSortableItem; i<index.length; i++) {
			for (int j=i; j<index.length; j++) {
				if (getBoxText(i).compareTo(getBoxText(j))>0) {
					int jIndex = index[j];
					index[j] = index[i];
					index[i] = jIndex;
				}
			}
		}
	}

	public void refresh()
	{
		list.clear();
		if (index.length!=getItemCount()) index = new int[getItemCount()];
		for (int i=0; i<index.length; i++) index[i] = i;
		if (sorted) sort();
		for (int i=0; i<index.length; i++) {
			String value = getBoxValue(i);
			String text = getBoxText(i);
			list.addItem(text!=null? text : NULL_TEXT, value);
			if (selectedSet.contains(value)) {
				list.setItemSelected(i, true);
			}
		}
	}
	
	public void setNumberSelected(long[] numbers)
	{
		selectedSet.clear();
		for (int i=0; i<numbers.length; i++) selectedSet.add(""+numbers[i]);
	}

	public void setNumberSelected(int[] numbers)
	{
		selectedSet.clear();
		for (int i=0; i<numbers.length; i++) selectedSet.add(""+numbers[i]);
	}
	
	public void setNumberSelected(long number)
	{
		selectedSet.clear();
		selectedSet.add(""+number);
	}
	
	public void clearSelected()
	{
		selectedSet.clear();
	}
	
	public long[] getSelectedListLong()
	{
		long[] result = new long[index.length];
		int count = 0;
		for (int i=0; i<index.length; i++) {
			if (list.isItemSelected(i)) {
				result[count++] = Long.parseLong(list.getValue(i));
			}
		}
		return Arrays.copyOf(result, count);
	}

	public int[] getSelectedList()
	{
		int[] result = new int[index.length];
		int count = 0;
		for (int i=0; i<index.length; i++) {
			if (list.isItemSelected(i)) {
				result[count++] = Integer.parseInt(list.getValue(i));
			}
		}
		return Arrays.copyOf(result, count);
	}
	
	public int getFirstSelected()
	{
		for (int i=0; i<index.length; i++) {
			if (list.isItemSelected(i)) return Integer.parseInt(list.getValue(i));
		}
		return -1;
	}
	
	public long getFirstSelectedLong()
	{
		for (int i=0; i<index.length; i++) {
			if (list.isItemSelected(i)) return Long.parseLong(list.getValue(i));
		}
		return -1;
	}

	abstract protected String getItemText(int index);
	
	abstract protected long getItemNumber(int index);
	
	abstract protected int getItemCount();
	
	public void addChangeListener(ChangeListener listener) 
	{
		listeners.add(listener);
	}

	public void removeChangeListener(ChangeListener listener) 
	{
		listeners.remove(listener);	
	}
	
	public void onChange(Widget sender)
	{
		listeners.fireChange(this);
	}
	
	public String getSelectedListString()
	{
		ListText text = new ListText();
		for (int i=0; i<index.length; i++) {
			if (list.isItemSelected(i)) {
				text.add(list.getItemText(i));
			}
		}
		return text.getText();		
	}
	
	public void setFirstSortableItem(int index)
	{
		firstSortableItem = index;
	}

	public int getFirstSortableItem() 
	{
		return firstSortableItem;
	}
	
	public void setEnabled(boolean b)
	{
		list.setEnabled(b);
	}

}
